<template>
	<div class="organ-manage-tree" :class="treeContainerClass">
		<div class="organ-manage-tree__top" style="padding-left: 5px">
			<slot name="tree-top"></slot>
		</div>
		<div class="organ-manage-tree__searchBar">
			<el-input
				v-model="treeSearchKey"
				placeholder="请输入内容"
				prefix-icon="el-icon-search"
				size="mini"
				class="organ-manage-tree__searchBar-input"
				@keyup.enter.native="onSearchInputEnter"
				@input="onSearchInput">
			</el-input>
			<w-icon
				type="tree-search-arrow-left"
				class="tree-search-arrow-icon"
				pointer
				@click="onTreeSearchArrowClick('pre')"
			></w-icon>
			<w-icon
				type="tree-search-arrow-right"
				class="tree-search-arrow-icon"
				pointer
				@click="onTreeSearchArrowClick('next')"
			></w-icon>
			<w-icon
				v-show="showTreeWidthExtendBtn"
				:type="treeContainerExtendFlag?'tree-width-extend':'tree-width-unextend'"
				class="tree-width-icon"
				pointer
				@click="onTreeContainerExtendClick"
			></w-icon>
		</div>
		<div class="organ-manage-tree__container">
			<w-scroll-bar scrollType="all">
				<el-tree
					ref="organTree"
					:data="treeData"
					:props="defaultProps"
					:expand-on-click-node="false"
					:filter-node-method="treeFilterNode"
					:show-checkbox="showCheckbox"
					:default-checked-keys="defaultCheckedKeys"
					:default-expand-all="false"
					:auto-expand-parent="false"
					:default-expanded-keys="defaultExpanedeKeys"
					node-key="id"
					highlight-current
					class="organ-manage-tree__content"
					:class="{'is-extend': treeContainerExtendFlag}"
					@node-click="onTreeItemClick"
					@check-change="onTreeCheckChange"
					@check="onTreeCheck">
					<div
						:ref="`ref-node-item-${data.id}`"
						:class="{
							'is-filter-tree-node': isSearchFilterTreeNode(data, node),
							'is-filter-tree-node-acitve': searchFilterTreeNodeList[searchFilterTreeIndex]&&searchFilterTreeNodeList[searchFilterTreeIndex].id===data.id
						}"
						class="organ-manage-tree__node-item"
						slot-scope="{ node, data }"
						@mouseover="onTreeItemMouseOver(data)"
						@mouseleave="onTreeItemMouseLeave"
					>
						<!-- <w-icon
							class="tree-extend-icon"
							:type="treeIconComputed(node)"
							@click="onTreeExtendClick(node)"
						></w-icon> -->
						<w-icon
							v-if="showTreeNodeIcon"
							:type="treeNodeIconComputed(data, node)"
						></w-icon>
						<el-tooltip :content="computecode(data.code || '', data[defaultProps.label])" placement="top-start" offset="-100" :enterable="false">
							<span
								class="organ-manage-tree__node-item-label fx-ellipsis"
								:class="{'is-extend': treeContainerExtendFlag}"
							>{{ data[defaultProps.label] }}</span>
						</el-tooltip>
						<slot :data="data" :activeTreeItemId="activeTreeItemId"></slot>
					</div>
				</el-tree>
			</w-scroll-bar>
		</div>
		<div class="organ-manage-tree__bottom">
			<slot name="tree-bottom"></slot>
		</div>
	</div>
</template>
<script>

export default {
	name: 'fx-tree',
	props: {
		treeData: {
			type: Array,
			default: () => {
				return []
			}
		},
		defaultProps: {
			type: Object,
			default: () => {
				return {
					children: 'children',
					label: 'name',
					code: 'code'
				}
			}
		},
		filterNode: Function,
		showTreeNodeIcon: Boolean,
		treeNodeIcon: {
			type: [String, Function],
			default: 'organ-type-group'
		},
		showCheckbox: Boolean,
		showTreeWidthExtendBtn: {
			type: Boolean,
			default: true
		},
		defaultChecked: {
			type: [Array, Function],
			default: () => {
				return []
			}
		}
	},
	data () {
		return {
			treeContainerExtendFlag: false,
			treeSearchKey: '',
			activeTreeItemId: null,
			searchFilterTreeIndex: -1,
			defaultCheckedKeys: [],
			defaultExpanedeKeys: []
		}
	},
	computed: {
		treeContainerClass () {
			return {
				'is-extend': this.treeContainerExtendFlag
			}
		},
		treeIconComputed (node) {
			return (node) => {
				if (node && node.childNodes.length !== 0) {
					if (node.expanded) {
						return 'tree-unextend'
					} else {
						return 'tree-extend'
					}
				} else {
					return ''
				}
			}
		},
		treeNodeIconComputed (data, node) {
			return (data, node) => {
				if (typeof this.treeNodeIcon === 'function') {
					return this.treeNodeIcon(data, node)
				} else {
					return this.treeNodeIcon
				}
			}
		},
		isSearchFilterTreeNode (data, node) {
			return (data, node) => {
				return this.treeSearchKey && this.$fxUtils.fuzzyQueryString(data[this.defaultProps.label], this.treeSearchKey) && node.visible
			}
		},
		searchFilterTreeNodeList () {
			const treeDataList = this.tree2Array(this.treeData)
			return treeDataList.filter(item => {
				if (this.$refs.organTree) {
					const node = this.$refs.organTree.getNode(item.id)
					return this.treeSearchKey && this.$fxUtils.fuzzyQueryString(item[this.defaultProps.label], this.treeSearchKey) && node.visible
				}
				return this.treeSearchKey && this.$fxUtils.fuzzyQueryString(item[this.defaultProps.label], this.treeSearchKey)
			})
		}
	},
	watch: {
		treeData: {
			immediate: true,
			handler (val) {
				if (val[0] && !this.$fxUtils.isDef(val[0].id)) {
					val[0].id = ''
				}
				this.setDefaultExpandedKeys(val)
				this.setDefaultChecked(val)
				this.$nextTick(() => {
					this.setFirstNodeSelected()
				})
			}
		}
	},
	methods: {
		computecode (code, lable) {
			return ((code || '') === 'all' ? '' : code) + ' ' + lable
		},
		getTreeRef () {
			return this.$refs.organTree
		},
		onTreeContainerExtendClick () {
			this.treeContainerExtendFlag = !this.treeContainerExtendFlag
			this.$emit('treeContainerExtend', this.treeContainerExtendFlag)
		},
		onTreeItemMouseOver (data) {
			this.activeTreeItemId = data.id
		},
		onTreeItemMouseLeave () {
			this.activeTreeItemId = null
		},
		onTreeItemClick (data, node) {
			this.$emit('node-click', data, node)
		},
		getCurrentNode () {
			return this.$refs.organTree.getCurrentNode()
		},
		onTreeExtendClick (node) {
			node.expanded = !node.expanded
			event.stopPropagation()
		},
		clearSrearchFilterTreeIndex () {
			this.searchFilterTreeIndex = -1
		},
		onSearchInput () {
			if (this.treeSearchKey === '') {
				this.clearSrearchFilterTreeIndex()
			}
		},
		clearSearchInput () {
			this.treeSearchKey = ''
		},
		onSearchInputEnter () {
			if (this.searchFilterTreeNodeList.length === 0) {
				return false
			}
			if (this.searchFilterTreeNodeList.length === 1 && this.searchFilterTreeIndex === 0) {
				return false
			}
			if (this.searchFilterTreeIndex === this.searchFilterTreeNodeList.length - 1) {
				this.searchFilterTreeIndex = 0
			} else {
				this.searchFilterTreeIndex = this.searchFilterTreeIndex + 1
			}
			this.expandTreeNode(this.searchFilterTreeNodeList[this.searchFilterTreeIndex])
			this.onTreeItemClick(this.searchFilterTreeNodeList[this.searchFilterTreeIndex])
		},
		expandTreeNode (treeNodeData) {
			const node = this.$refs.organTree.getNode(treeNodeData.id)
			this.expandAll(node)
			this.$nextTick(() => {
				this.scrollTopNode(treeNodeData.id)
			})
		},
		expandAll (node) {
			node.expanded = true
			if (node.parent) {
				this.expandAll(node.parent)
			}
		},
		scrollTopNode (key) {
			this.$fxUtils.doScrollTop(this.$refs[`ref-node-item-${key}`])
		},
		tree2Array (tree) {
			return this.$fxUtils.arrFlatten(tree, item => {
				return item[this.defaultProps.children]
			})
		},
		onTreeSearchArrowClick (action) {
			if (this.searchFilterTreeNodeList.length === 0) {
				return false
			}
			if (this.searchFilterTreeNodeList.length === 1 && this.searchFilterTreeIndex === 0) {
				return false
			}
			if (action === 'next') {
				if (this.searchFilterTreeIndex === this.searchFilterTreeNodeList.length - 1) {
					this.searchFilterTreeIndex = 0
				} else {
					this.searchFilterTreeIndex = this.searchFilterTreeIndex + 1
				}
			} else {
				if (this.searchFilterTreeIndex === 0) {
					this.searchFilterTreeIndex = this.searchFilterTreeNodeList.length - 1
				} else {
					this.searchFilterTreeIndex = this.searchFilterTreeIndex - 1
				}
			}
			this.onTreeItemClick(this.searchFilterTreeNodeList[this.searchFilterTreeIndex])
		},
		treeFilterNode (value, data) {
			if (typeof this.filterNode === 'function') {
				return this.filterNode(value, data)
			}
			return true
		},
		setFirstNodeSelected () {
			if (this.treeData[0]) {
				this.$refs.organTree.setCurrentKey(this.treeData[0].id)
			}
		},
		filter (flag) {
			this.$refs.organTree.filter(flag)
			this.resetSearch()
		},
		resetSearch () {
			this.searchFilterTreeIndex = -1
		},
		onTreeCheckChange (data, checked, indeterminate) {
			this.$emit('check-change', data, checked, indeterminate)
		},
		onTreeCheck (data, treeCheckData) {
			this.$emit('check', data, treeCheckData)
		},
		setDefaultChecked (treeData) {
			if (this.$fxUtils.toRawType(this.defaultChecked) === 'Array') {
				this.defaultCheckedKeys = this.defaultChecked
			} else if (this.$fxUtils.toRawType(this.defaultChecked) === 'Function') {
				this.defaultCheckedKeys = this.filterDefaultCheckedKeys(this.$fxUtils.deepClone(treeData), this.defaultChecked).map(item => {
					return item.id
				})
			} else {
				this.defaultCheckedKeys = []
			}
		},
		setDefaultExpandedKeys (treeData) {
			this.defaultExpanedeKeys = treeData.map(item => {
				return item.id
			})
		},
		filterDefaultCheckedKeys (treeData, fn) {
			const deepGetChild = function (child, fn) {
				return child.every(item => {
					if (item.children) {
						return fn(item) && deepGetChild(item.children, fn)
					} else {
						return fn(item)
					}
				})
			}
			const list = treeData.reduce((pre, cur) => {
				let child = cur[this.defaultProps.children] || []
				if (fn(cur) && (child.length === 0 || (deepGetChild(child, fn) && child.length > 0))) {
					cur = [cur]
				} else {
					cur = []
				}
				cur = cur.concat(child = this.filterDefaultCheckedKeys(child, fn))
				return pre.concat(cur)
			}, [])
			return list
		},
		getCheckedKeys (leafOnly = false, includeHalfChecked = false, filterFn) {
			let checkeds = this.getTreeRef().getCheckedNodes(leafOnly, includeHalfChecked)
			if (filterFn) {
				checkeds = checkeds.filter(filterFn)
			}
			return checkeds.map(item => {
				return item.id
			})
		},
		getAllCheckedKeys (fn) {
			return this.getCheckedKeys(false, true, fn)
		}
	}
}
</script>
<style lang="stylus" scoped>
@import '~$assets/stylus/varsty.styl'
.organ-manage-tree {
	background-color: $fxWhite
	width: 220px
	display: flex
	flex-direction: column
	transition: width 0.2s
	&.is-extend {
		width: 350px
		transition: width 0.2s
	}
	&__searchBar {
		display: flex
		flex-direction: row
		padding: 0 5px
		align-items: center;
		margin-bottom: 5px
		height: 40px
		&-input {
			flex: 1
		}
		.tree-width-icon, .tree-search-arrow-icon {
			margin-left: 5px
			width: 15px
			height: 15px
		}
	}
	&__container {
		flex: 1
		overflow: auto;
		>>>.el-tree-node__content {
			height: 34px
		}
		// >>>.el-icon-caret-right {
		// 	display: none
		// }
		>>>.el-tree-node__children {
			overflow: visible;
		}
		.organ-manage-tree__content {
			display: inline-block
			min-width: 200px
			&.is-extend {
				min-width: 350px;
			}
		}
		.organ-manage-tree__node-item {
			display: flex;
			flex-direction: row;
			align-items: center;
			padding-right: 60px
			// width: 180px;
			&-label {
				overflow: hidden
				max-width: 150px;
				flex: 1;
				&.is-extend {
					max-width: 300px;
				}
			}
			.tree-node-tools-btn {
				width: 20px
				height: 20px
				margin: 0px 5px
			}
		}
		.tree-extend-icon {
			width: 14px
			height: 14px
			margin-right:5px
			margin-left: 5px
			box-sizing: border-box
		}
		.is-filter-tree-node {
			.organ-manage-tree__node-item-label {
				color: $fxDefaultColor
			}
		}
		.is-filter-tree-node-acitve {
			.organ-manage-tree__node-item-label {
				font-weight: 900
				font-size: 13px
			}
		}
	}
}
</style>
